Skip to content

feat(harness): make the whole gate policy host-supplied, not just the gated-tool set - #1715

Merged
pyramation merged 1 commit into
mainfrom
feat/host-gate-policy
Aug 13, 2026
Merged

feat(harness): make the whole gate policy host-supplied, not just the gated-tool set#1715
pyramation merged 1 commit into
mainfrom
feat/host-gate-policy

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1714. That PR made the gated set injectable, but the gate still knew Constructive's tools by name: buildConfirmPrompt's switch over the 17 db tools, manage_entity_types action: 'list' as a read, and the tokenless add_records/create_api_key skips were all inline in createConfirmGate. A remote coding host injecting bash got gating, a generic dialog, and no way to say "gate rm -rf and force-push, not ls".

All of that moves behind one host-supplied GatePolicy; the gate keeps only the mechanics (decline memory, declined-retry auto-skip, headless block, calling confirmTool).

type GatePolicy = {
  isGated(event: GateToolCallEvent): boolean;                      // sync, no I/O
  resolvePrompt(event, cwd): Promise<ConfirmPrompt | null>;         // null = let it through
};

resolvePrompt returning null is what generalises the two Constructive read/skip exceptions: "gated by name, but this call needs no decision" (unrunnable project, missing data token) is now a policy statement, not a branch in the gate. It runs only for gated calls on a host with a confirm surface, so it may do I/O — that's where the create_template preview lookup lives.

Constructive's behaviour is unchanged and becomes the default implementation, createConstructiveGatePolicy(deps), applied when a caller passes the old deps bag:

type ConfirmGateOptions = ConfirmGateDeps | { policy: GatePolicy };

const policy = 'policy' in options ? options.policy : createConstructiveGatePolicy(options);

ConfirmGateDeps (now an alias of ConstructiveGateDeps, gatedTools knob included) and MUTATING_DB_TOOLS are untouched, so Desktop/CLI and the pi extension in agentic/pi/src/index.ts need no change. The pi adapter gained the same union so a pi host with no Constructive project doesn't have to invent a resolveProjectContext. ConfirmPrompt moved from gating/prompts.ts (Constructive-specific wording) to gating/preview.ts next to ConfirmPreview, since policy.ts must not import the Constructive prompts to name its own return type; it's still re-exported from the package root.

Tests: the existing suite covers the default policy end-to-end (unchanged, including the argument-level manage_entity_types read and the tokenless skips). New cases drive the gate with a shell-host policy that gates bash only for rm -rf/push --force — proving argument-level gating, host-authored prompt text, null waving a gated call through, delete_table no longer gated despite being in MUTATING_DB_TOOLS, and that decline memory plus the headless block still apply to a policy the harness knows nothing about.

Link to Devin session: https://app.devin.ai/sessions/d57afe90832a4d7197b9b41ff4ca4f43
Requested by: @pyramation

@pyramation pyramation self-assigned this Aug 13, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit c3ca367 into main Aug 13, 2026
20 checks passed
@pyramation
pyramation deleted the feat/host-gate-policy branch August 13, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant